#include "modbus_tcp_slave.h"
#include "ui_modbus_tcp_slave.h"
#include <QModbusDataUnit>
#include <QSerialPort>
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
#include <QSerialPortInfo>
#include <QModbusServer>
#include <QModbusRtuSerialSlave>

modbus_tcp_slave::modbus_tcp_slave(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::modbus_tcp_slave)
{
    ui->setupUi(this);

    //初始化界面元素
    if (!modbusDevice) {
        setupModbusSlave();
    }

    setupRegistersTable();
    updateUiState(false);

    this->centralWidget()->setLayout(ui->verticalLayout);

}

modbus_tcp_slave::~modbus_tcp_slave()
{
    if (modbusDevice)
        modbusDevice->disconnectDevice();
    delete ui;
}

bool modbus_tcp_slave::isValidIp(const QString &ipString)
{
    QHostAddress address(ipString);

    if(address.protocol() == QAbstractSocket::IPv4Protocol)
    {
        return true;
    }

    return false;
}

void modbus_tcp_slave::on_connectButton_clicked()
{
    if (modbusDevice->state() != QModbusDevice::ConnectedState) {
        //服务器参数设置
        QString ipAddr = ui->tcpIP->text();
        if(isValidIp(ipAddr))
        {
            modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ipAddr); //windows环境等多IP地址的情况下需要设置
            modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter,ui->tcpPort->value());
            modbusDevice->setServerAddress(ui->serverAddressSpin->value());  // 设置服务器地址(Modbus从站地址)
        }
        else
        {
            QMessageBox::warning(this,tr("Error"),tr("输入的IP地址不合法"));
            return;
        }

#if  0
        // 设置数据存储
        modbusServer->setMap({
            { QModbusDataUnit::Coils, { true, false, true, true } },          // 线圈
            { QModbusDataUnit::DiscreteInputs, { false, true, false } },      // 离散输入
            { QModbusDataUnit::InputRegisters, { 0, 1000, 2000, 3000 } },     // 输入寄存器
            { QModbusDataUnit::HoldingRegisters, { 10, 20, 30, 40, 50 } }     // 保持寄存器
        });
#endif

        if (!modbusDevice->connectDevice()) {
            QMessageBox::critical(this, tr("Error"), tr("Connect failed: ") + modbusDevice->errorString());
        } else {
            updateUiState(true);
        }
    } else {
        modbusDevice->disconnectDevice();
        updateUiState(false);
    }
}

void modbus_tcp_slave::updateRegisterValue(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
    Q_UNUSED(bottomRight)

    if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState)
        return;

    int row = topLeft.row();
    int column = topLeft.column();

    if (column == 3) { // 只有值列变化时才更新
        QModelIndex typeIndex = registersModel->index(row, 0);
        QModelIndex addrIndex = registersModel->index(row, 2);
        QModelIndex valueIndex = registersModel->index(row, 3);

        QString type = registersModel->data(typeIndex).toString();
        quint16 address = registersModel->data(addrIndex).toUInt();
        quint16 value = registersModel->data(valueIndex).toUInt();

        QModbusDataUnit::RegisterType regType;

        if (type == "Coil") {
            regType = QModbusDataUnit::Coils;
        } else if (type == "Discrete Input") {
            regType = QModbusDataUnit::DiscreteInputs;
        } else if (type == "Input Register") {
            regType = QModbusDataUnit::InputRegisters;
        } else if (type == "Holding Register") {
            regType = QModbusDataUnit::HoldingRegisters;
        } else {
            return; // 未知类型
        }

        // 创建一个包含单个寄存器的数据单元
        QModbusDataUnit unit(regType, address, 1);
        unit.setValue(0, value); // 设置新值

        // 正确设置数据到Modbus设备
        if (!modbusDevice->setData(unit)) {
            QMessageBox::warning(this, tr("Error"), tr("Could not set register value"));
        }
    }
}

void modbus_tcp_slave::handleDeviceError(QModbusDevice::Error error)
{
    if (error == QModbusDevice::NoError)
        return;

    QMessageBox::warning(this, tr("Device Error"), modbusDevice->errorString());
}

void modbus_tcp_slave::setupModbusSlave()
{
    ui->tcpPort->setRange(0,32767);                 //设置IP端口的范围
    ui->serverAddressSpin->setRange(0,300);         //设置服务器地址范围

    modbusDevice = new QModbusTcpServer(this);
    connect(modbusDevice, &QModbusServer::errorOccurred, this, &modbus_tcp_slave::handleDeviceError);
    // 监听数据变化
    connect(modbusDevice, &QModbusServer::dataWritten,
            [](QModbusDataUnit::RegisterType table, int address, int size) {
        qDebug() << "数据被写入 - 表:" << table;
        if(QModbusDataUnit::Coils == table)
        {
            qDebug() << "数据类型:" << "coils"
                     << "地址:" << address
                     << "大小:" << size;
        }
        else if(QModbusDataUnit::DiscreteInputs == table)
        {
            qDebug() << "数据类型:" << "DiscreteInputs"
                     << "地址:" << address
                     << "大小:" << size;
        }
        else if(QModbusDataUnit::HoldingRegisters == table)
        {
            qDebug() << "数据类型:" << "HoldingRegisters"
                     << "地址:" << address
                     << "大小:" << size;
        }
        else if(QModbusDataUnit::InputRegisters == table)
        {
            qDebug() << "数据类型:" << "InputRegisters"
                     << "地址:" << address
                     << "大小:" << size;
        }


    });

    // 处理状态变化
    connect(modbusDevice, &QModbusServer::stateChanged,
            [](QModbusDevice::State state) {
        qDebug() << "服务器状态改变:" << state;
        if(state == QModbusDevice::ConnectedState)
        {
            //modbusDevice->disconnectDevice();
            //updateUiState(false);
        }
    });


    // 设置Modbus数据存储,每种类型寄存器10个数据
    QModbusDataUnitMap reg;
    reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
    reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
    reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
    reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

    modbusDevice->setMap(reg);  //设置数据存储
}

void modbus_tcp_slave::setupRegistersTable()
{
    registersModel = new QStandardItemModel(0, 4, this);
    registersModel->setHorizontalHeaderLabels({"Type", "Active", "Address", "Value"});

    // 添加示例数据
    QStringList types = {"Coil", "Discrete Input", "Input Register", "Holding Register"};

    for (const QString &type : types) {
        for (int i = 0; i < 10; ++i) {
            QList<QStandardItem*> rowItems;
            rowItems << new QStandardItem(type);
            rowItems << new QStandardItem("Yes");
            rowItems << new QStandardItem(QString::number(i));
            rowItems << new QStandardItem(QString::number(0));
            registersModel->appendRow(rowItems);
        }
    }

    ui->registersTable->setModel(registersModel);
    ui->registersTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

    connect(registersModel, &QStandardItemModel::dataChanged,
            this, &modbus_tcp_slave::updateRegisterValue);
}

void modbus_tcp_slave::updateUiState(bool connected)
{
    ui->connectButton->setText(connected ? tr("Disconnect") : tr("Connect"));
    ui->tcpPort->setEnabled(!connected);
    ui->tcpIP->setEnabled(!connected);
    ui->serverAddressSpin->setEnabled(!connected);
}

